﻿using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;
using Zxcvbn;
/// <summary>
/// 高性能泛型对象转换器（基于表达式树）
/// </summary>
/// <typeparam name="TIn">
/// 源类型。必须具有可被反射访问的公共实例属性。
/// </typeparam>
/// <typeparam name="TOut">
/// 目标类型。必须具有 public 无参构造函数和可被反射访问的公共实例属性。
/// </typeparam>
public static class TransExpV2<
    [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
TIn,
    [DynamicallyAccessedMembers(
        DynamicallyAccessedMemberTypes.PublicParameterlessConstructor |
        DynamicallyAccessedMemberTypes.PublicProperties)]
TOut>
{
    private static readonly Func<TIn, TOut> cache = GetFunc();

    private static Func<TIn, TOut> GetFunc()
    {
        ParameterExpression parameter = Expression.Parameter(typeof(TIn), "p");
        var bindings = new List<MemberBinding>();

        // 遍历 TOut 的所有可写公共实例属性
        foreach (PropertyInfo outProp in typeof(TOut).GetProperties(BindingFlags.Public | BindingFlags.Instance))
        {
            if (!outProp.CanWrite)
                continue;

            // 在 TIn 中查找同名、可读、类型兼容的公共实例属性
            var inProp = typeof(TIn).GetProperty(
                outProp.Name,
                BindingFlags.Public | BindingFlags.Instance);

            if (inProp?.CanRead == true &&
                (outProp.PropertyType.IsAssignableFrom(inProp.PropertyType) ||
                 inProp.PropertyType.IsAssignableFrom(outProp.PropertyType)))
            {
                MemberExpression sourceValue = Expression.Property(parameter, inProp);
                MemberBinding binding = Expression.Bind(outProp, sourceValue);
                bindings.Add(binding);
            }
        }

        NewExpression newExpr = Expression.New(typeof(TOut));
        MemberInitExpression initExpr = Expression.MemberInit(newExpr, bindings.ToArray());
        Expression<Func<TIn, TOut>> lambda = Expression.Lambda<Func<TIn, TOut>>(initExpr, parameter);

        return lambda.Compile();
    }

    /// <summary>
    /// 执行转换
    /// </summary>
    public static TOut Trans(TIn input) => cache(input);
}


public static class CloneExtends
{
    // T 同时作为 TIn 和 TOut，需同时满足两者要求
    public static T DeepCloneObject<
        [DynamicallyAccessedMembers(
            DynamicallyAccessedMemberTypes.PublicProperties |
            DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
    T>(this T t) where T : class
        => TransExpV2<T, T>.Trans(t);

    public static IList<T> DeepCloneList<
        [DynamicallyAccessedMembers(
            DynamicallyAccessedMemberTypes.PublicProperties |
            DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
    T>(this IList<T> tList) where T : class
    {
        if (tList == null) return null!;
        var result = new List<T>(tList.Count);
        foreach (var item in tList)
        {
            result.Add(DeepCloneObject(item));
        }
        return result;
    }

    // ✅ 关键修复：T 作为 TIn，必须声明 PublicProperties
    //    ResultT 作为 TOut，必须声明 PublicProperties + PublicParameterlessConstructor
    public static ResultT CopyToAll<
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
    T,
        [DynamicallyAccessedMembers(
            DynamicallyAccessedMemberTypes.PublicProperties |
            DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
    ResultT>(this T source)
        where T : class
    {
        return TransExpV2<T, ResultT>.Trans(source);
    }

    public static void CopyToAll<
        [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)]
    T,
        [DynamicallyAccessedMembers(
            DynamicallyAccessedMemberTypes.PublicProperties |
            DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)]
    ResultT>(this T source, out ResultT result)
        where T : class
    {
        result = TransExpV2<T, ResultT>.Trans(source);
    }
}